View Javadoc
1   package org.apache.maven.surefire.junit;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.lang.reflect.InvocationHandler;
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  import java.util.HashSet;
26  import java.util.Set;
27  import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
28  import org.apache.maven.surefire.report.ReportEntry;
29  import org.apache.maven.surefire.report.RunListener;
30  import org.apache.maven.surefire.report.SimpleReportEntry;
31  
32  /**
33   * Invocation Handler for TestListener proxies to delegate to our {@link RunListener}
34   *
35   */
36  public class TestListenerInvocationHandler
37      implements InvocationHandler
38  {
39      // The String names of the four methods in interface junit.framework.TestListener
40      private static final String START_TEST = "startTest";
41  
42      private static final String ADD_FAILURE = "addFailure";
43  
44      private static final String ADD_ERROR = "addError";
45  
46      private static final String END_TEST = "endTest";
47  
48      private final Set<FailedTest> failedTestsSet = new HashSet<FailedTest>();
49  
50      private RunListener reporter;
51  
52      private static final Class[] EMPTY_CLASS_ARRAY = new Class[]{ };
53  
54      private static final String[] EMPTY_STRING_ARRAY = new String[]{ };
55  
56      private static class FailedTest
57      {
58          private Object testThatFailed;
59  
60          private Thread threadOnWhichTestFailed;
61  
62          FailedTest( Object testThatFailed, Thread threadOnWhichTestFailed )
63          {
64              if ( testThatFailed == null )
65              {
66                  throw new NullPointerException( "testThatFailed is null" );
67              }
68  
69              if ( threadOnWhichTestFailed == null )
70              {
71                  throw new NullPointerException( "threadOnWhichTestFailed is null" );
72              }
73  
74              this.testThatFailed = testThatFailed;
75  
76              this.threadOnWhichTestFailed = threadOnWhichTestFailed;
77          }
78  
79          public boolean equals( Object obj )
80          {
81              boolean retVal = true;
82  
83              if ( obj == null || getClass() != obj.getClass() )
84              {
85                  retVal = false;
86              }
87              else
88              {
89                  FailedTest ft = (FailedTest) obj;
90  
91                  if ( ft.testThatFailed != testThatFailed )
92                  {
93                      retVal = false;
94                  }
95                  else if ( !ft.threadOnWhichTestFailed.equals( threadOnWhichTestFailed ) )
96                  {
97                      retVal = false;
98                  }
99              }
100 
101             return retVal;
102         }
103 
104         public int hashCode()
105         {
106             return threadOnWhichTestFailed.hashCode();
107         }
108     }
109 
110     public TestListenerInvocationHandler( RunListener reporter )
111     {
112         if ( reporter == null )
113         {
114             throw new NullPointerException( "reporter is null" );
115         }
116 
117         this.reporter = reporter;
118     }
119 
120     public Object invoke( Object proxy, Method method, Object[] args )
121         throws Throwable
122     {
123         String methodName = method.getName();
124 
125         if ( methodName.equals( START_TEST ) )
126         {
127             handleStartTest( args );
128         }
129         else if ( methodName.equals( ADD_ERROR ) )
130         {
131             handleAddError( args );
132         }
133         else if ( methodName.equals( ADD_FAILURE ) )
134         {
135             handleAddFailure( args );
136         }
137         else if ( methodName.equals( END_TEST ) )
138         {
139             handleEndTest( args );
140         }
141 
142         return null;
143     }
144 
145     // Handler for TestListener.startTest(Test)
146     public void handleStartTest( Object[] args )
147     {
148         ReportEntry report = new SimpleReportEntry( args[0].getClass().getName(), args[0].toString() );
149 
150         reporter.testStarting( report );
151     }
152 
153     // Handler for TestListener.addFailure(Test, Throwable)
154     private void handleAddError( Object[] args )
155         throws IllegalAccessException, InvocationTargetException
156     {
157         ReportEntry report = SimpleReportEntry.withException( args[0].getClass().getName(), args[0].toString(),
158                                                               getStackTraceWriter( args ) );
159 
160         reporter.testError( report );
161 
162         failedTestsSet.add( new FailedTest( args[0], Thread.currentThread() ) );
163     }
164 
165     private LegacyPojoStackTraceWriter getStackTraceWriter( Object[] args )
166         throws IllegalAccessException, InvocationTargetException
167     {
168         String testName;
169 
170         try
171         {
172             Method m = args[0].getClass().getMethod( "getName", EMPTY_CLASS_ARRAY );
173             testName = (String) m.invoke( args[0], EMPTY_STRING_ARRAY );
174         }
175         catch ( NoSuchMethodException e )
176         {
177             testName = "UNKNOWN";
178         }
179 
180         return new LegacyPojoStackTraceWriter( args[0].getClass().getName(), testName, (Throwable) args[1] );
181     }
182 
183     private void handleAddFailure( Object[] args )
184         throws IllegalAccessException, InvocationTargetException
185     {
186         ReportEntry report = SimpleReportEntry.withException( args[0].getClass().getName(), args[0].toString(),
187                                                               getStackTraceWriter( args ) );
188 
189         reporter.testFailed( report );
190 
191         failedTestsSet.add( new FailedTest( args[0], Thread.currentThread() ) );
192     }
193 
194     private void handleEndTest( Object[] args )
195     {
196         boolean testHadFailed = failedTestsSet.remove( new FailedTest( args[0], Thread.currentThread() ) );
197 
198         if ( !testHadFailed )
199         {
200             ReportEntry report = new SimpleReportEntry( args[0].getClass().getName(), args[0].toString() );
201 
202             reporter.testSucceeded( report );
203         }
204     }
205 }